<?php

/*
	Class: Resource

	About: Author
		Jaybill McCarthy

	About: License
		<http://communit.as/docs/license>

	About: See Also
		<Cts_Controller_Action_Abstract>
		<Cts_Controller_Action_Admin>
*/
class ResourceController extends Cts_Controller_Action_Admin {

	/* Group: Instance Methods */

	/*
		Function: init
			Invoked automatically when an instance is created.
			Initializes the current instance.
			Initializes the parent object (calls init() on the parent instance).
	*/
    function init() {
		parent::init();
    }

	/* Group: Actions */

	/*
		Function: edit
			Edit which resources a role has access to by module.
			
		HTTP GET or POST Parameters:
			id - role id to edit resources for (id, not shortname)
			modid - module id of module to edit resources for. defaults to 'default'

		View Variables:
			actions - An array of all available actions in the app.
			pagetitle - The HTML page title.
			role - array containing the role information for the chosen role
			modid - id of the current module				
			module_title - Name of the current module, pulled from module.ini        
       		enabled_modules - An array of modules that are currently enabled  
	*/
    function editAction() {
    	
    	$request = new Cts_Request($this->getRequest());
    	
    	$modules_table = new Modules();
    	$roles_resources_table = new RolesResources();
    	
    	if($request->has("id")){
    		$role_id = $request->id;    	 
	    	$roles_table = new Roles();
	    	$role = $roles_table->fetchRow("id = " . $role_id);
	    	if(!is_null($role)){
	    		$this->view->role = $role->toArray();
	    		$this->view->roleshortname = $role->shortname;
	    	} else {
	    		$this->_redirect("/role");
	    	}
    	} else {
    		$this->_redirect("/role");
    	}
    	
    	if($request->has("modid")){
    		if($modules_table->exists($request->modid)){
    			$module_id = $request->modid;
    		} else {
    			$module_id = "default";
    		}    		
    	} else {
    		$module_id = "default";
    	}
    	
    	
    	
		if ($this->getRequest()->isPost()) {
         	$resources = $this->getRequest()->getPost('resource');
         	
         	// Hose everything for this role and module
         	$where = $roles_resources_table->getAdapter()->quoteInto("role_id = ? and " , $role_id);
         	$where .= $roles_resources_table->getAdapter()->quoteInto("module = ? " , $module_id);		
			$roles_resources_table->delete($where);

         	foreach ($resources as $resource) {
         		$resource_array = explode("-", $resource);
         		$resource_module = $resource_array[0];
         		$resource_controller = $resource_array[1];
         		$resource_action = $resource_array[2];         		
         		$data = array(
         			'role_id' => $role_id,
         			'module' => $resource_module,
         			'controller' => $resource_controller,
         			'action' => $resource_action,
         		);         		
         		$roles_resources_table->insert($data);
         	}         	         	
         	$this->view->success = $this->_T("Resources updated.");
         }
    	
    	
    	$db_roles_resources = $roles_resources_table->fetchAll('role_id = ' . $role_id );    	
    	
    	$resources = array();
    	
    	foreach ($db_roles_resources as $resource){
			if(!array_key_exists($resource->module,$resources)){
				$resources[$resource->module] = array();
			}
    		if(!array_key_exists($resource->controller, $resources[$resource->module])){
				$resources[$resource->module][$resource->controller] = array();
			}
			$resources[$resource->module][$resource->controller][] = $resource->action;			
    	}

    	/*
    	 * This is a poor man's introspector. The reflection API needs the classes acutally available, 
    	 * which creates naming conflicts between modules. What I do instead is read the physical files, 
    	 * line by line, find the lines with "function fooAction" and determine that the action name is
    	 * "foo". It's a hack, but it works.
    	 */
    	
    	$all_actions = array();
    	$modules = array();
		$controllerdirs = array();    	
    	

    	$enabled_modules = $modules_table->getEnabledModules();
    	
    	foreach($enabled_modules as $enabled_module){
    		$controllerdirs[$enabled_module] = Zend_Registry::get("basepath")."/modules/".$enabled_module."/controllers";
    	}
    	
    	$controllerdir = $controllerdirs[$module_id];
    	    	
    	
        $d = dir($controllerdir);
        $modules[] = $module_id;
		while (false !== ($entry = $d->read())) {
		   if($entry != '.' and $entry != '..' and $entry != '.svn'){
		   	 if($module_id == "default"){
		   	 	$controller_name = substr($entry, 0, stripos($entry, 'Controller.php'));
		   	 } else {
		   	 	$controller_name = substr($entry, 0, stripos($entry, 'Controller.php'));
		   	 	if(substr($controller_name, 0, 1) == "_"){
		   	 		$controller_name = substr($controller_name, stripos($controller_name, '_') + 1);
		   	 	}
		   	 }
		   	 $lines = file($controllerdir . '/' . $entry );
		   	 foreach($lines as $line){
		   	 	$line = trim($line);
		   	 	$function_location = stripos($line, 'function');
		   	 	if($function_location !== false and $function_location == 0){
		   	 		$function_name = substr($line, $function_location);
		   	 		$action_location = stripos($function_name, 'Action');
		   	 		if($action_location !== false){
		   	 			$allowed = false;
		   	 			$inherited = false;
		   	 			$action_name = trim(substr($function_name, $function_location + 9));
		   	 			$action_name = substr($action_name, 0, stripos($action_name, 'Action'));
		   	 			if(array_key_exists($module_id, $resources)){
		   	 				if(array_key_exists($controller_name, $resources[$module_id])){
				   	 			if (in_array($action_name, $resources[$module_id][$controller_name])){
				   	 				$allowed = true;
				   	 			}
		   	 				}
			   	 			
		   	 			}
		   	 			if(!is_null($role->inherits_id)){			   	 			
		   	 				$inherited = $this->isResourceInherited($module_id, $controller_name, $action_name, $role_id);
		   	 			}
		   	 			$all_actions[$module_id][$controller_name][$action_name] = array(
		    			    'allowed' => $allowed,
		    			    'inherited' => $inherited,
		   	 			);
		   	 		}
		   	 	}
		   	 }
		   }
		}
		$d->close();
		$this->view->modid = $module_id;
		$mod_cfg = $modules_table->parseIni($module_id);		
		$this->view->module_title = $mod_cfg['general']['name'];
        $this->view->actions = $all_actions;
        
        $this->view->modules = $enabled_modules;        
    }

	/* Group: Private or Protected Methods */

	/*
		Function: isResourceInherited
			Used by <edit> to determine if the permissions on a resource are inherited from another role.

		Arguments:
			$module - The name of the module for the resource in question.
			$controller - The name of the controller for the resource in question.
			$action - The name of the action for the resource in question.
			$role_id - The ID of the role in question.

		Returns:
			A boolean indicating whether the permissions on the indicated resource are inherited from another role.
	*/
    protected function isResourceInherited($module, $controller, $action, $role_id) {
		$inheritsResource = false;
		$roles_table = new Roles();
		$roles_resources_table = new RolesResources();

		// obtain the current role    	
		$role = $roles_table->fetchRow('id=' . $role_id);

		// if this role inherits a role, get that role
		$foo = $role->inherits_id;
		if (!is_null($role->inherits_id)) {
			$parent_role = $roles_table->fetchRow('id=' . $role->inherits_id);
			// determine if parent has access to this resource
			$roles_resource = $roles_resources_table->fetchRow(
			"role_id=" . $parent_role->id . " and " .
			"module='" . $module . "' and " .
			"controller='" . $controller . "' and " .
			"action='" . $action . "' ");

			if (is_null($roles_resource)) {
				//parent doesn't have it, check to see if parent inherits any role
				if (!is_null($parent_role->inherits_id)) {
					//parent inherits role, recurse
					$inheritsResource = $this->isResourceInherited($module, $controller, $action, $role->inherits_id);
				}
			} else {
				//parent has it, role is inherited
				$inheritsResource = true;
			}
		}
		return $inheritsResource;
    }    
}
